/*
 * Copyright (c) 2010-2013 meituan.com
 * All rights reserved.
 * 
 */
package com.scm.common.utils.http;

import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.BasicClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.util.*;

/**
 * 使用httpclient发送请求工具类
 */
@Slf4j
public class MagHttpUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(MagHttpUtil.class);

    public final static String CLIENT_SOCKET_TIMEOUT_KEY = "http.socket.timeout";
    public final static String CLIENT_CONNECTION_TIMEOUT_KEY = "http.connection.timeout";
    public final static String CLIENT_RETRY_KEY =  "retry";


    private final static String CONTENT_TYPE = "Content-Type";
    private final static String CONTENT_TYPE_JSON = "application/json";
    private final static String EMPTY_JSON = "{}";
    private final static String JSON_KEY = "json";
    private final static String LOCAL_IP = "127.0.0.1";

    private MagHttpUtil() {

    }


    public static class Result {

        int code;

        String context;

        String reason;

        public int getCode() {
            return code;
        }

        public Result setCode(int code) {
            this.code = code;
            return this;
        }

        public String getContext() {
            return context;
        }

        public Result setContext(String context) {
            this.context = context;
            return this;
        }

        public String getReason() {
            return reason;
        }

        public Result setReason(String reason) {
            this.reason = reason;
            return this;
        }

        @Override
        public String toString() {
            return "Result{" +
                    "code=" + code +
                    ", context='" + context + '\'' +
                    ", reason='" + reason + '\'' +
                    '}';
        }
    }


    public static final Result getReturnCode(String url, Map params, Map clientParams, Map headers) {
        DefaultHttpClient client = new DefaultHttpClient(new BasicClientConnectionManager());
        HttpGet get = new HttpGet(buildUrl(url, params));
        try {
            //设置url
            //设置header
            setHeader(get, headers);
            //设置client信息
            setClientParams(client, url, clientParams);

            HttpResponse response = client.execute(get);
            String str = EntityUtils.toString(response.getEntity());
            return new Result().setCode(response.getStatusLine().getStatusCode()).setContext(str)
                    .setReason(response.getStatusLine().getReasonPhrase());
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            client.getConnectionManager().shutdown();
        }
    }


    public static final String get(String url, Map params, Map clientParams, Map headers) {
        try {
            Result result = getReturnCode(url, params, clientParams, headers);
            //设置client信息
            if(HttpStatus.SC_OK == result.getCode()) {
                return result.getContext();
            }
            LOGGER.error("http invoke fail,url:{}, status:{}, reason:{}", url,
                    result.getCode(), result.getReason());
            return StringUtils.EMPTY;
        }catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            return StringUtils.EMPTY;
        }
    }



    public static final Result postReturnCode(String url, Map params , Map clientParams, Map headers) {
        DefaultHttpClient client = new DefaultHttpClient(new BasicClientConnectionManager());
        HttpPost post = new HttpPost(url);
        try {
            //设置client信息
            setClientParams(client, url, clientParams);
            //设置header
            setHeader(post, headers);
            //设置json
            buildBody(post, params, headers);

            HttpResponse response = client.execute(post);

            String str = EntityUtils.toString(response.getEntity());
            return new Result().setCode(response.getStatusLine().getStatusCode()).setContext(str)
                    .setReason(response.getStatusLine().getReasonPhrase());
        } catch (Exception e) {
            LOGGER.error("postReturnCode fail, url={}, error={}", url, e.getMessage(), e);
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            client.getConnectionManager().shutdown();
        }
    }

    public static final Result postJSONReturnCode(String url, Object object , Map clientParams, Map headers) {
        headers = ObjectUtils.defaultIfNull(headers, Collections.emptyMap());
        headers.put(CONTENT_TYPE, CONTENT_TYPE_JSON);
        object = ObjectUtils.defaultIfNull(object, Collections.emptyMap());
        Map<String,String> params = new HashMap();

        String json = new Gson().toJson(object);
        log.info(json);
        params.put(JSON_KEY, json);
        return postReturnCode(url, params, clientParams, headers);
    }


    public static final String post(String url, Map params , Map clientParams, Map headers) {
        try {
            Result result = postReturnCode(url, params, clientParams, headers);
            //设置client信息
             if(HttpStatus.SC_OK == result.getCode()) {
                return result.getContext();
            }
            LOGGER.error("http invoke fail,url:{}, status:{}, reason:{}", url,
                    result.getCode(), result.getReason());
            return StringUtils.EMPTY;
        }catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            return StringUtils.EMPTY;
        }
    }


    private static String buildUrl(String url, Map params) {
        params = ObjectUtils.defaultIfNull(params, Collections.emptyMap());
        if (StringUtils.isBlank(url)) {
            return url;
        }
        StringBuilder builder = new StringBuilder(url);
        if (params.isEmpty()) {
            return builder.toString();
        }

        if (url.indexOf("?") == -1) {
            builder.append("?");
        } else {
            builder.append("&");
        }
        //do easy
        Iterator keys = params.keySet().iterator();
        while (keys.hasNext()) {
            Object key = keys.next();
            builder.append(key).append("=").append(params.get(key)).append("&").toString();
        }
        return builder.toString().replaceAll("&$", "");
    }

    private static void setHeader(HttpRequestBase base, Map header) {
        header = ObjectUtils.defaultIfNull(header, Collections.emptyMap());
        Iterator keys = header.keySet().iterator();
        while (keys.hasNext()) {
            Object key = keys.next();
            base.setHeader(key.toString(), header.get(key).toString());
        }
    }

    private static void buildJsonBody(HttpPost post, String json) throws UnsupportedEncodingException {
        StringEntity entity = new StringEntity(json, "UTF-8");//解决中文乱码问题
        entity.setContentEncoding("UTF-8");
        post.setEntity(entity);
    }

    private static void buildBody(HttpPost post, Map params, Map headers) throws UnsupportedEncodingException {
        Object value = headers.get(CONTENT_TYPE);
        if (value != null && value instanceof String && StringUtils.equalsIgnoreCase((String) value, CONTENT_TYPE_JSON)) {
            Object json = params.get(JSON_KEY);
            log.info(String.valueOf(json));
            buildJsonBody(post, ObjectUtils.defaultIfNull(json, EMPTY_JSON).toString());
            return;
        }

        params = ObjectUtils.defaultIfNull(params, Collections.emptyMap());
        Iterator keys = params.keySet().iterator();
        List<NameValuePair> nvps = new ArrayList <NameValuePair>();
        while (keys.hasNext()) {
            Object key = keys.next();
            nvps.add(new BasicNameValuePair(key.toString(), params.get(key).toString()));
        }
        post.setEntity(new UrlEncodedFormEntity(nvps, "utf-8"));
    }


    private static void setClientParams(DefaultHttpClient client, String url, Map clientParams) {
        clientParams = ObjectUtils.defaultIfNull(clientParams, Collections.emptyMap());
        if (clientParams.containsKey(CLIENT_SOCKET_TIMEOUT_KEY)) {
            client.getParams().setParameter(CLIENT_SOCKET_TIMEOUT_KEY,
                    MapUtils.getIntValue(clientParams, CLIENT_SOCKET_TIMEOUT_KEY));
        }

        if (clientParams.containsKey(CLIENT_CONNECTION_TIMEOUT_KEY)) {
            client.getParams().setParameter(CLIENT_CONNECTION_TIMEOUT_KEY,
                    MapUtils.getIntValue(clientParams, CLIENT_CONNECTION_TIMEOUT_KEY));
        }

        if (clientParams.containsKey(CLIENT_RETRY_KEY)) {
            client.setHttpRequestRetryHandler(getRetryHandler(url,
                    MapUtils.getIntValue(clientParams, CLIENT_RETRY_KEY)));
        }
    }


    private static HttpRequestRetryHandler getRetryHandler(String url, int retry) {
        return (exception, executionCount, context) -> {
            if (executionCount > retry) {
                return false;
            } else {
                LOGGER.info("retry " + executionCount + " " + url + " -> " + exception.getMessage());
                return true;
            }
        };
    }


    public static void main(String[] args) {

        MagHttpUtil.Result resp = MagHttpUtil.getReturnCode("http://ysxb.csu.edu.cn/rc-pub/front/front-article/getArticleByDoi?doi=10.11817%2Fj.ysxb.1004.0609.2022-43772&timestamps=1704681802464",null,null,null);
        System.out.println(11);

    }

}
